#  说明:
#      处理git repo的类。
#  注意：
#      1、加载配置文件，加配置文件中的项目节点存入list。
#      2、循环遍历节点list，获取repo数据：
#        （1）根据GIT PULL参数，是/否（1/0）拉取代码。
#        （2）组织git命令，获取数据到临时文件。
#        （3）遍历临时文件，提取需要的数据，并写入csv中。
#      3、删除临时文件，写入最后提取日期。

import re
import os
import configparser
import csv
import static_variables


class GitCommitClient(object):
    """
        获取当前git目录中的信息
    """

    def __init__(self, conf):
        """
            函数说明：初始化类
            参数：配置文件名称
        """
        # git数据是/否（1/0）发写csv文件
        self.writecsv = "1"
        # git pull状态拉取/不拉取（1/0）
        self.gitpull = "0"
        # 配置文件中的项目
        self.projects = []
        # 全局统计代码数文件的扩展名列表
        self.pub_exts = []
        # 初始化配置
        self.__init_conf(conf)
        return

    def __init_conf(self, conf):
        """
            函数说明：初始化配置
            参数：配置文件名称
            返回值：无
        """
        # 配置文件名称
        self.conf = conf
        # 实例化configParser对象
        self.config = configparser.ConfigParser()
        # read读取ini文件
        self.config.read(self.conf, encoding="utf-8")
        # 遍历ini中的项目，并存入list
        for section in self.config.sections():
            if section == "system":
                # 获取全局参数
                config_system = self.config["system"]
                self.gitpull = config_system.get("GITPULL", "0")
                self.writecsv = config_system.get("writecsv", "1")
                try:
                    static_variables.DEBUG = int(config_system.get("debug", 0))
                except:
                    pass
                tmp_ext = config_system.get("pub_exts", "")
                if len(tmp_ext) > 0:
                    self.pub_exts = str.upper(tmp_ext).split(",")
            elif section == "rbtinfo":
                continue
            else:
                # 获取项目列表
                self.projects.append(section)
        return

    def get_gitrepo(self):
        """
            函数说明：获取当前git目录的repo
            参数：无
            返回值：repo名称
        """
        git_repo = ""
        os_ret = os.system("git remote -v >" + static_variables.TEMP_FILE_GIT)
        if os_ret == 0:
            try:
                with open(static_variables.TEMP_FILE_GIT, 'r', encoding="utf-8") as f1:
                    # with open(static_variables.TEMP_FILE_GIT, 'r') as f1:
                    lst_giturl = f1.readlines()
                for str_url in lst_giturl:
                    try:
                        lst_tmp = str_url.replace("\n", "").split("/")
                        git_repo = re.sub(".git.*", "", lst_tmp[len(lst_tmp) - 1])
                        git_repo = git_repo.replace("(fetch)", "").replace(" ", "")
                        git_repo = git_repo.replace("(push)", "")
                        if len(git_repo) > 0:
                            break
                    except:
                        pass

            finally:
                f1.close()
        return git_repo

    def get_pid_cid(self, project):
        """
            函数说明：根据节点名，获取ProjectID与ClientID
            参数：项目节点名
            返回值：0，成功；其它：失败
        """
        lst_temp = project.split("_")
        try:
            # 项目ID
            RepoID = int(lst_temp[1])
            # ProjectID = project.replace("PRO_", ""))
        except:
            RepoID = -1
        # try:
        #     # 项目ID
        #     ClientID = int(lst_temp[2])
        # except:
        #     ClientID = " "
        return RepoID
            # , ClientID

    def each_projects(self):
        """
            函数说明：遍历项目list，依次获取数据
            参数：无
            返回值：无
        """
        if len(self.projects) == 0:
            return 3
        # 循环遍历项目
        for project in self.projects:
            self.get_project(project)

        return 0

    def get_project(self, project):
        """
            函数说明：遍历项目对应的repo，依次获取数据每个库中的数据
            参数：项目节点名
            返回值：0，成功；其它：失败
        """
        # 获取projectID与ClientID
        RepoID = self.get_pid_cid(project)
        # 获取项目中的所有库信息
        repos = self.config.options(project)
        if len(repos) == 0:
            print("The library for project %s was not found." % project)
            return 1
        repos.sort()
        # 获取项目节点
        config_project = self.config[project]
        # 循环遍历项目中对应的库
        for repo in repos:
            pro_info = {
                "project": project,
                "repo": repo,
                "repoid": RepoID

            }
            iLen = len(repo)
            # 只取库路径配置
            if (iLen == 0) or (repo[iLen - 4: iLen].upper() == "DATE"):
                continue
            # 获取当前库配置
            pro_info["repo_path"] = config_project.get(repo, "")
            pro_info["repo_since"] = config_project.get(repo + "_startDATE", "")
            pro_info["repo_until"] = config_project.get(repo + "_untilDATE", "")
            tmp_repoext = config_project.get(repo + "_EXTS", "")
            pro_info["repo_exts"] = []
            try:
                if len(tmp_repoext) != 0:
                    pro_info["repo_exts"] = str.upper(tmp_repoext).split(",")
            except:
                pass
            if os.path.exists(pro_info["repo_path"]):
                self.create_repodata(pro_info)
            else:
                if static_variables.DEBUG == 1:
                    print("Path %s does not exist." % pro_info["repo_path"])

        return 0

    def repo_gitpull(self):
        """
            函数说明：根据系统参数，执行git pull
            参数：无
            返回值：0：成功；其它：失败
        """
        if self.gitpull == "1":
            ret = os.system("git pull")
            if static_variables.DEBUG == 1:
                print(ret)
        else:
            if static_variables.DEBUG == 1:
                print(type(self.gitpull), self.gitpull)

    def create_repodata(self, pro_info):
        """
            函数说明：根据临时文件，生成可以导入QMS中的csv数据文件
            参数：
                pro_info = {
                        project: 项目节点名称
                        repo：节点名称
                        repoid： 项目ID
                        clientid：客户端ID
                        repo_path：git repo路径
                        repo_since：开始时间
                        repo_until:结束时间
                        repo_exts: 提取文件list，不在此列表中文件跳过
                        }
            返回值：0：成功；其它：失败
        """
        global lst_csv_nm, lst_csv_m
        ret = 0
        # 进入git库路径
        os.chdir(pro_info["repo_path"])
        # 获取git repor名称
        repo_name = self.get_gitrepo()
        if repo_name == "":
            if static_variables.DEBUG == 1:
                print("%s is not a Git repo path." % pro_info["repo_path"])
            return 1
        self.del_temp_file(static_variables.TEMP_FILE_GIT)
        # 拉取代码
        self.repo_gitpull()
        # git log 默认命令
        self.git_str = 'git log --all --pretty=format:"@@@%H;%cn;%aE;%as" --numstat --date=iso '
        if pro_info["repo_since"] != "" or pro_info["repo_until"] != "":
            self.git_str += ' --since="' +pro_info["repo_since"]+ ' 00:00:00"'
            self.git_str += ' --until="' + pro_info["repo_until"] + ' 23:59:59"'
        # 要保存的csv文件名
        save_file = os.path.join(static_variables.TARGET_DIR, repo_name + ".csv")

        # 处理merge数据
        # 生成临时文件
        if static_variables.DEBUG == 1:
            print(self.git_str + " --merges")
        os_ret = os.system(self.git_str + " --merges >" + static_variables.TEMP_FILE_M)

        if os_ret != 0:
            print("Failed to get merges, os_ret = %d" % os_ret)
            # return os_ret
        else:
            # 统计merge的git log并保存
            lst_csv_m = self.total_gitlog(static_variables.TEMP_FILE_M, 1, repo_name, pro_info)

        # 处理no merge数据
        # 生成临时文件
        if static_variables.DEBUG == 1:
            print(self.git_str + " --no-merges")
        os_ret = os.system(self.git_str + " --no-merges >" + static_variables.TEMP_FILE_NM)
        if os_ret != 0:
            print("Failed to get no-merges, os_ret = %d" % os_ret)
            # return os_ret
        else:
            # 统计merge的git log并保存
            lst_csv_nm = self.total_gitlog(static_variables.TEMP_FILE_NM, 0, repo_name, pro_info)

        if len(lst_csv_m) != 0 or len(lst_csv_nm) != 0:
            # 删除文件
            if os.path.exists(save_file):
                os.remove(save_file)
            # 增加配置，是/否写入csv文件
            if self.writecsv == "1":
                # merge数据
                self.write_csv(save_file, lst_csv_m)
                # no merge数据
                self.write_csv(save_file, lst_csv_nm)
                print("Get git log: " + save_file)
            # 重写配置文件
            self.write_repodate(pro_info)
        else:
            print("The git repository is empty.")
            ret = 1
        return ret

    def total_gitlog(self, TEMP_FILE, m_flag, repo_name, pro_info):
        """
            函数说明：根据list中的内容，
            参数：
                TEMP_FILE：保存git log的文件名
                m_flag： merge状态
                repo_name：库名
                pro_info = {
                        project: 项目节点名称
                        repo：节点名称
                        repoid： 项目ID
                        clientid：客户端ID
                        repo_path：git repo路径
                        repo_since：开始时间
                        }
            返回值：git log的list
        """
        # 返回值，默认为空
        lst_ret = []
        try:
            with open(TEMP_FILE, 'r', encoding="utf-8") as f1:
                lst_git = f1.readlines()
            # 文件有数据
            if len(lst_git) > 0:
                i_add = 0
                i_del = 0
                lst_log = []
                # 遍历数据
                for line in lst_git:
                    # 跳过空行
                    if len(line) == 0:
                        continue
                    if line[0:3] == "@@@":
                        # 保存完成的git log
                        if len(lst_log) != 0:
                            lst_log.append(i_add)
                            lst_log.append(i_del)
                            lst_log.append(repo_name)
                            lst_log.append(pro_info["repoid"])
                            lst_ret.append(lst_log)
                            if static_variables.DEBUG == 1:
                                print(lst_log)
                        # 新统计
                        lst_log = re.sub(r' \+.*', "", line[3:].replace("\n", "")).split(";")
                        if static_variables.DEBUG == 1:
                            print(line)
                        i_add = 0
                        i_del = 0
                    else:
                        # 统计add与del数量
                        lst_tmp = line.replace("\n", "").replace("}", "").split("\t")
                        if static_variables.DEBUG == 1:
                            print(lst_tmp)
                        # 增加过滤文件
                        try:
                            tmp_exts = str.upper(lst_tmp[2]).split(".")
                            if static_variables.DEBUG == 1:
                                print(tmp_exts)
                            tmp_ext = tmp_exts[len(tmp_exts) - 1]
                            # 判断当前库提取文件扩展名
                            if len(pro_info["repo_exts"]) != 0:
                                if not tmp_ext in pro_info["repo_exts"]:
                                    continue
                            # 当前库未配置，查看全局提取文件扩展名
                            elif len(self.pub_exts) != 0:
                                if not tmp_ext in self.pub_exts:
                                    continue
                        except:
                            continue
                        try:
                            i_add += int(lst_tmp[0])
                        except:
                            pass
                        try:
                            i_del += int(lst_tmp[1])
                        except:
                            pass
                # 处理最后一行的git log
                if len(lst_log) != 0:
                    lst_log.append(i_add)
                    lst_log.append(i_del)
                    lst_log.append(repo_name)
                    lst_log.append(pro_info["repoid"])
                    lst_ret.append(lst_log)
        finally:
            f1.close()
        return lst_ret



    def write_csv(self, csv_name, lst_csv):
        '''
            函数说明：将list中的数据，保存到csv数据文件
            参数：
                1、csv文件名（string)。
                2、git数据（list)
            返回值：无
        '''
        if len(lst_csv) == 0:
            return
        try:
            # with open(csv_name, 'a+', newline='') as csvfile:
            with open(csv_name, 'a+', newline='', encoding="utf-8") as csvfile:
                writer = csv.writer(csvfile)
                if static_variables.DEBUG == 1:
                    print(csv_name, len(lst_csv))
                for row in lst_csv:
                    writer.writerow(row)
        finally:
            csvfile.close()
        return


    def write_repodate(self, pro_info):
        """
            函数说明：将git库提取的最后日期写到配置文件
            参数：
                pro_info = {
                        project: 项目节点名称
                        repo：节点名称
                        repoid： 仓库ID
                        clientid：客户端ID
                        repo_path：git repo路径
                        repo_since：开始时间
                        }
            返回值：无
        """
        # try:
        #     if static_variables.DEBUG == 1:
        #         print(pro_info["project"], pro_info["repo"] + "_DATE", static_variables.NOW)
        #     self.config.set(pro_info["project"], pro_info["repo"] + "_DATE", static_variables.NOW)
        #     self.config.write(open(self.conf, "r+", encoding="utf-8"))
        #     # self.config.write(open(self.conf, "r+"))
        # except Exception as e:
        #     print(repr(e))

    def del_temp_file(self, TEMP_FILE=""):
        """
            函数说明：删除临时文件
            参数：
                无
            返回值：无
        """
        if static_variables.DEBUG == 1:
            return
        if len(TEMP_FILE) != 0:
            if os.path.exists(TEMP_FILE):
                os.remove(TEMP_FILE)
        else:
            if os.path.exists(static_variables.TEMP_FILE_M):
                os.remove(static_variables.TEMP_FILE_M)
            if os.path.exists(static_variables.TEMP_FILE_NM):
                os.remove(static_variables.TEMP_FILE_NM)
        return
